package token

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"

	"gitverse.ru/EYMikhievich/api-gigachat/internal/modules/clientGigaChat/config"
)

type TokenUpdater struct {
	TokenURL     string
	RqUID        string
	Scope        string
	AuthHeader   string
	Token        string
	Client       *http.Client
	UpdatePeriod time.Duration
}

func NewTokenUpdater(cfg config.ConfigAPIGigachat) (*TokenUpdater, error) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	duration, err := time.ParseDuration(cfg.UpdatePeriodToken)
	if err != nil {
		return nil, fmt.Errorf("Ошибка преобразования в time.Duration %v :", err)

	}

	return &TokenUpdater{
		TokenURL:     cfg.URLReceiveToken,
		AuthHeader:   cfg.AuthorizeData,
		RqUID:        cfg.ClientID,
		Scope:        cfg.Scope,
		Client:       &http.Client{Transport: tr},
		UpdatePeriod: duration,
	}, nil
}

func (t *TokenUpdater) UpdateToken() error {
	req, err := http.NewRequest("POST", t.TokenURL, bytes.NewBuffer([]byte(fmt.Sprintf("scope=%s", t.Scope))))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Authorization", fmt.Sprintf("Basic %s", t.AuthHeader))
	req.Header.Set("RqUID", t.RqUID)

	resp, err := t.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		bodyBytes, _ := io.ReadAll(resp.Body)
		bodyString := string(bodyBytes)
		return fmt.Errorf("получен код ответа, отличный от 200: %d, тело: %s", resp.StatusCode, bodyString)
	}

	var result map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return err
	}

	newToken, ok := result["access_token"].(string)
	if !ok {
		return fmt.Errorf("токен доступа не найден в ответе")
	}

	t.Token = newToken
	return nil
}

func (t *TokenUpdater) Start() {
	ticker := time.NewTicker(t.UpdatePeriod)
	go func() {
		for {
			<-ticker.C
			if err := t.UpdateToken(); err != nil {
				fmt.Printf("Ошибка обновления токен: %v\n", err)
			} else {
				fmt.Println("Токен успешно обновлен")
			}
		}
	}()
}
